/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
// String.cpp: implementation of the String class.
//
//////////////////////////////////////////////////////////////////////

#include "ssi_string.h"

#ifdef __OLD_STRING__

#include <stdio.h>
#include <stdarg.h>
#include <memory.h>
#include <String.h>
#include <ctype.h>
#include "ssi_string.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

String::String()
{
  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;
  str = SSI_NULL;
  str = new SSI_CHAR[1];
  str[0] = SSI_NULL;
	//str = 0;
}

String::String(const SSI_CHAR* InitVal)
{
	START_PROFILE("String::String(cchar)");

  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;
  //str = SSI_NULL;
  //SSI_INT64 Len = GetSize(InitVal);
  //str = new SSI_CHAR[Len+1];
  //loc_copy(InitVal, str);

	SSI_INT64 Len = strlen(InitVal);
	// This will always be null
	//if(str) delete str;
  str = new SSI_CHAR[Len+1];  
	str = (SSI_CHAR*)memcpy( (void*)str, (const void *)InitVal, Len );
	str[Len] = SSI_NULL;



	START_PROFILE("String::String(cchar)");
}

String::String(SSI_CHAR InitChar)
{
  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;
  
	Format("%c", InitChar);
}

String::String(const String& Other)
{
	START_PROFILE("String::String(Other)");

  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;

	SSI_INT64 Len = strlen(Other.str);
	// This will always be null
	//if(str) delete str;
  str = new SSI_CHAR[Len+1];  
	str = (SSI_CHAR*)memcpy( (void*)str, (const void *)Other.str, Len );
	str[Len] = SSI_NULL;
	
  //str = SSI_NULL;
  //SSI_INT64 Len = GetSize(Other.str);
  //str = new SSI_CHAR[Len+1];
	//loc_copy(Other.str, str);

	STOP_PROFILE("String::String(Other)");
}

String::~String()
{
  Null();
}

SSI_CHAR* String::Null()
{
  if(str)
  {
    delete [] str;
    str = SSI_NULL;
  }
  return str;
}

SSI_INT64 String::GetSize(const SSI_CHAR *InStr)
{
  if(InStr == SSI_NULL) return 0;
  SSI_INT64 Ret = 0;
  Ret = (SSI_INT64)strlen(InStr);
  
  
  //while(*InStr++ != SSI_NULL)
  //{
  //  Ret++;
  //}
  
  return Ret;
}

const SSI_CHAR* String::Str() const
{
  return str;
}

SSI_INT64 String::loc_copy(const SSI_CHAR *src, SSI_CHAR *dest)
{
  if(src == SSI_NULL) return SSI_NULL;
  if(dest == SSI_NULL) return SSI_NULL;

  SSI_INT64 Len = 0;
  Len = GetSize(src);

  dest = (SSI_CHAR*)memcpy( (void*)dest, (const void *)src, Len );
  dest[Len] = SSI_NULL;
  return Len;
}

String& String::operator =(const String &Other)
{
	START_PROFILE("String::=(Other)");
	SSI_INT64 Len = strlen(Other.str);
	Null();
  str = new SSI_CHAR[Len+1];  
	str = (SSI_CHAR*)memcpy( (void*)str, (const void *)Other.str, Len );
	str[Len] = SSI_NULL;
	STOP_PROFILE("String::=(Other)");
  return *this;
}

String& String::operator =(const SSI_CHAR* Other)
{
	START_PROFILE("String::=(cchar)");
	SSI_INT64 Len = strlen(Other);
	Null();
  str = new SSI_CHAR[Len+1];  
	str = (SSI_CHAR*)memcpy( (void*)str, (const void *)Other, Len );
	str[Len] = SSI_NULL;
	STOP_PROFILE("String::=(cchar)");
	return *this;
}

bool String::operator<(const String& Other) const
{
	if(strcmp(str, Other.Str()) < 0){
		return true;
	}
	return false;
}

bool String::operator<(const SSI_CHAR* Other) const
{
	if(strcmp(str, Other) < 0){
		return true;
	}
	return false;
}


String String::operator +(String s2)
{

	START_PROFILE("String::+(Other)");
  SSI_INT64 iLen1 = GetLength();
  SSI_INT64 iLen2 = s2.GetLength();
  SSI_INT64 ctr = 0;
  SSI_CHAR* Temp = new SSI_CHAR[iLen1+iLen2+1];

  for(ctr = 0; ctr < iLen1; ctr++)
  {
    Temp[ctr] = str[ctr];
  }
  for(ctr = iLen1; ctr < (iLen1+iLen2); ctr++)
  {
    Temp[ctr] = s2[ctr-iLen1];
  }
  Temp[ctr] = SSI_NULL;
	String Ret = Temp;
	delete [] Temp;
  STOP_PROFILE("String::+(Other)");

	return Ret;
}

String String::operator +(SSI_CHAR* s2)
{
  return operator+(String(s2));
}

/*
SSI_CHAR& String::operator [](SSI_INT64 i)
{
  if(i > GetSize(str)-1)
  {
    SSI_INT64 ctr = 0;
    
    SSI_CHAR* Temp = new SSI_CHAR[GetLength()+1];
    loc_copy(str, Temp);

    Null();
    str = new SSI_CHAR[i+2];  // Must be +2 because need to append another SSI_NULL to end
    for(ctr = 0; ctr < GetSize(Temp); ctr++)
    {
      str[ctr] = Temp[ctr];
    }
    for(ctr = ctr; ctr <= i+1; ctr++)
    {
      str[ctr] = SSI_NULL;
    }
    delete Temp;
  }
  return str[i];
}
*/

SSI_INT64 String::GetLength() const
{
	if(!str) return 0;
	return strlen(str);
  //return GetSize(str);
}


SSI_BOOL String::operator ==(String &Other) const
{
  // It may be slightly quicker to keep these checks
	//SSI_INT64 i1 = strlen(str);        //GetLength();
	//SSI_INT64 i2 = strlen(Other.str);  //Other.GetLength();
	if(strcmp(str, Other.str)){
		return 0;
	}else{
		return 1;
	}
}

SSI_BOOL String::operator ==(const SSI_CHAR* Other) const
{
	if(strcmp(str, Other)){
		return 0;
	}else{
		return 1;
	}
}

SSI_INT64 String::Replace(const SSI_CHAR *Out, const SSI_CHAR *In)
{
	START_PROFILE("String::Replace");
  SSI_INT64 Ret = 0;
  SSI_INT64 iOut = strlen(Out);//GetSize(Out);
  SSI_INT64 iIn = strlen(In);  //GetSize(In);
  SSI_INT64 ctr = 0;

  SSI_INT64 Sz = strlen(str);  //GetLength();
  
  if(iOut <= 0){
    return 0;
  }

  String T2;
  String T3;

  if(Sz < iOut) return 0;

  for(ctr = 0; ctr < Sz; ctr++)
  {
    T3 = SubString(ctr, ctr + iOut - 1);
    if(T3 == Out)
    {
        if(ctr > 0)
        {
          T2 = SubString(0, ctr-1);
        }
        T3 = SubString(ctr + iOut, Sz);
        T2 = T2 + In + T3;
        *this = T2;
        ctr = ctr + iIn - 1;
        Sz = GetLength();
        Ret++;
    }
  }
	STOP_PROFILE("String::Replace");
  return Ret;
}

String String::SubString(SSI_INT64 Start, SSI_INT64 Finish) const
{
	START_PROFILE("String::SubString");
	SSI_INT64 Len = strlen(str);
  if((Finish < 0) || (Finish > (Len - 1))) Finish = Len - 1;
  if(Start < 0) Start = 0;
  if(Start > Finish)
  {
		return String(""); // An empty string
  }
	SSI_CHAR oc = str[Finish+1];  // This is inclusive
	SSI_CHAR* temp = str + Start;
	str[Finish+1] = 0;
	String Ret;
	Ret = temp;
	str[Finish+1] = oc;
	STOP_PROFILE("String::SubString");
	return Ret;

}

SSI_INT64 String::Find(const String &In, SSI_INT64 StartPos, SSI_INT64 StopPos) const
{
  // This whole function could be made quicker...
	// Actually, it is probably as quick as it can get, and still 
	//  do the quote processing, etc...

	// Temporarily replace all \\\\ with sp

	SSI_INT64 len = GetLength();
	if(len <= 0) return -1;
	char *pdest;

	SSI_INT64 Ret = -1;
	char sp2[3];
	sp2[0] = 1;
	sp2[1] = 1;
	sp2[2] = 0;
	//char esc[3];
	//esc[0] = '\\';
	//esc[1] = '\\';
	//esc[2] = 0;
	char* esc = "\\\\";
	
	String s;
	//s.Null();
	//s.str = strdup(str);

	//char* tempstr = strdup(str);
	s = str;//tempstr;
	//delete [] tempstr;

	int offset = 0;
	/*
	while(pdest = strstr(s.str + offset, esc)){
		*pdest = 1;
		pdest++;
		*pdest = 1;
		offset = (int)(pdest - s.str);
	}
	*/
	
	SSI_INT64 i = s.Replace(esc, sp2);

	offset = StartPos-1;
	int qoffset = 0;
	int qctr = 0;

	char *qdest;
	char t = 0;
	char check[2];
	check[0] = CHECK_WITHIN_SSI_CHAR_START;
	check[1] = 0;
	char bDoCheck = 0;
	int bGo = 1;

	if(offset < -1){
		offset = -1;
	}else if(offset >= len){
		offset = GetLength();
	}

	if(StopPos >= len){
		StopPos = len;
	}

	if(CHECK_WITHIN_SSI_CHAR_START && CHECK_WITHIN_SSI_CHAR_END){
		bDoCheck = 1;
	}

	if(StopPos >= 0){
		s.str[StopPos] = 0;  // avoid going past the stop position
	}
	while((pdest = strstr(s.str + offset + 1, In.str)) && bGo){
		offset = (int)(pdest - s.str);
		
		t = s.str[offset];
		s.str[offset] = 0;

		// Check if within start chars
		qoffset = -1;
		qctr = 0;
		if(bDoCheck){
			while(qdest = strstr(s.str + qoffset + 1, check)){
				qoffset = (int)(qdest - s.str);
				if(check[0] == CHECK_WITHIN_SSI_CHAR_END){
					if(s.str[qoffset - 1] == ESCAPE_SSI_CHAR){
					}else{
						qctr++;
					}
				}else{
					qctr++;
				}
				if(qctr % 2){
					check[0] = CHECK_WITHIN_SSI_CHAR_START;
				}else{
					check[0] = CHECK_WITHIN_SSI_CHAR_END;
				}
				
			}
		}

		// See if char on opposite side
		if(qctr % 2){
		}else{
			Ret = offset;
			bGo = 0;
		}
		s.str[offset] = t;
	}

/*	
	esc[0] = 1;
	esc[1] = 1;
	offset = 0;
	while(pdest = strstr(s.str + offset, esc)){
		*pdest = ESCAPE_SSI_CHAR;
		pdest++;
		*pdest = ESCAPE_SSI_CHAR;
		offset = (int)(pdest - s.str);
	}
*/
	//s.Replace(sp2, esc); // Dont need this, I think...

	return Ret;

	/*
	Replace(sp, "\\\\");


	 char *pdest;
   int  result;
   //printf( "String to be searched:\n   %s\n", string );
   //printf( "   %s\n   %s\n\n", fmt1, fmt2 );
   pdest = strstr( string, str );
   result = (int)(pdest - string + 1);
   if ( pdest != SSI_NULL )
      //printf( "%s found at position %d\n", str, result );
   else
      //printf( "%s not found\n", str );


/*

  SSI_INT64 start = StartPos;
  SSI_INT64 stop = StopPos;
	SSI_INT64 InLen = strlen(In.str);  //In.GetLength();
	SSI_INT64 Len = strlen(str);       //GetLength();

  SSI_CHAR q_char = '\"';
  SSI_CHAR escape_char = '\\';
  SSI_BOOL bDO_CHECK = 1;
  if(start < 0) start = 0;
  if(stop < 0) stop = Len;

  if(InLen > Len) return -1;

  String Temp;
  SSI_INT64 i = 0;
  SSI_INT64 q_ctr = 0;


  for(i = start; i < stop; i++)
  {
    bDO_CHECK = 1;
    if(str[i] == CHECK_WITHIN_SSI_CHAR_START)
    {
      if(i >= 1)
      {
        if(str[i - 1] != escape_char)
        {
          q_ctr++;
        }
      }
      else
      {
        q_ctr++;
      }
    }
    if((str[i] == CHECK_WITHIN_SSI_CHAR_END) && (CHECK_WITHIN_SSI_CHAR_END != CHECK_WITHIN_SSI_CHAR_START))
    {
      if(i >= 1)
      {
        if(str[i - 1] != escape_char)
        {
          q_ctr--;
        }
      }
      //else
      //{
      //  q_ctr++;
      //}
    }


    if(str[i] == In.str[0])
    {
      if(i > 0)
      {
        if(str[i-1] == CHECK_BEFORE_SSI_CHAR) bDO_CHECK = 0;
      }
      if((i + InLen) < stop)
      {
        if(str[i+InLen] == CHECK_AFTER_SSI_CHAR) bDO_CHECK = 0;
      }
      if(CHECK_WITHIN_SSI_CHAR_START)
      {
        if(In.str[0] == CHECK_WITHIN_SSI_CHAR_START)
        {
          q_ctr--;
        }
        if(In.str[0] == CHECK_WITHIN_SSI_CHAR_END)
        {
          q_ctr++;
        }

        if(q_ctr % 2)
        {
          bDO_CHECK = 0;
        }
      }
      //else
      //{
      //  bDO_CHECK = 1;
      //}

      if(bDO_CHECK)
      {
        Temp = SubString(i, i + InLen - 1);
        if(Temp == In)
        {
          return i;
        }
      }
    }
  }
  return -1;
	*/
}

SSI_INT64 String::Find(const SSI_CHAR* In, SSI_INT64 StartPos, SSI_INT64 StopPos) const
{
  return Find(String(In), StartPos, StopPos);
}

String String::Left(SSI_INT64 NumChars) const
{
  if(NumChars <= 0)
  {
    return "";
  }
  return String(SubString(0, NumChars-1));
}

String String::Right(SSI_INT64 NumChars) const
{
  SSI_INT64 Len = strlen(str);  //GetLength();
  return String(SubString(Len - NumChars));
  // BECAUSE REMEMBER SubString is INCLUSIVE
}

//SSI_INT64 String::Parse(const char* Delimeters, String &Return, String* Tok, SSI_INT64 DelLen){
//	return Parse(String(Delimeters), Return, Tok, DelLen);
//}

SSI_INT64 String::Parse(String& Delimeters, StringTree& Return, SSI_INT64 DelLen){
	SSI_INT64 ctr = 1;        // There will be at least one
	String RetStr;
	while(Parse(Delimeters, RetStr, 0, DelLen) >= 0){
		Return.push(RetStr);
		ctr++;
	}
	Return.push(*this);   // Add the last element
	return ctr;
}


SSI_INT64 String::Parse(String& Delimeters, String &Return, String* Tok, SSI_INT64 DelLen)
{
	//  This is probably as optimal as it will get...
  SSI_INT64 Len = strlen(Delimeters.str);  //Delimeters.GetLength();
  if(DelLen < 1) DelLen = 1;
  if(DelLen > Len) DelLen = Len;

  if(Len == 0) return -1;
  SSI_INT64 i = 0;
  SSI_INT64 Pos = 0;
  SSI_INT64 Min = -1;
  for(i = 0; i < Len; i++)
  {
    if( (Pos = Find( Delimeters.SubString( i, i+DelLen-1 ) ))  >= 0)
    {
      if((Pos < Min) || (Min < 0))
      {
        Min = Pos;
        if(Tok)
        {
          *Tok = SubString(Pos, Pos+DelLen-1);
        }
      } 
    }
  }
  if(Min == 0){
    Return = "";
    *this = SubString(Min+DelLen);
    return 0;
  }else if(Min < 0){
    Return = "";
    return -1;
  }else{
		Return = SubString(0, Min-1);
    *this = SubString(Min+DelLen);
    return Min;
  }  
}

void String::TrimLeft()
{
  SSI_INT64 Len = strlen(str);  //GetLength();
  SSI_INT64 i;
  SSI_INT64 Pos = -1;
  if(Len <= 0) return;
  for(i = 0; i < Len; i++)
  {
    SSI_CHAR T = str[i];  //GetAt(i);
    if((T != '\t') && (T != ' ') && (T != '\r') && (T != '\n'))
    {
      break;
    }
    else
    {
      Pos = i;
    }
  }
  if(Pos < 0) return;
  *this = SubString(Pos+1);
}

void String::TrimRight()
{
  SSI_INT64 Len = strlen(str);//GetLength();
  SSI_INT64 i;
  SSI_INT64 Pos = -1;
  if(Len <= 0) return;
  for(i = Len-1; i >= 0; i--)
  {
    SSI_CHAR T = str[i];//GetAt(i);
    if((T != '\t') && (T != ' ') && (T != '\r') && (T != '\n'))
    {
      break;
    }
    else
    {
      Pos = i;
    }
  }
  if(Pos == 0) *this = "";
  else if(Pos < 0) return;
  else *this = SubString(0, Pos-1);
}

void String::Trim()
{
  TrimLeft();
  TrimRight();
}

SSI_CHAR String::GetAt(SSI_INT64 Pos) const
{
  if(Pos > static_cast<SSI_INT64>(strlen(str))) return SSI_NULL;
  if(Pos < 0) return SSI_NULL;
  return str[Pos];  
}

void String::SetQuoteState(SSI_BOOL bSet)
{
  if(bSet) CHECK_WITHIN_SSI_CHAR_END = CHECK_WITHIN_SSI_CHAR_START = Q_SSI_CHAR;
  else CHECK_WITHIN_SSI_CHAR_END = CHECK_WITHIN_SSI_CHAR_START = SSI_NULL;
  //if(bSet) CHECK_QUOTE_STATE = 1;
  //else CHECK_QUOTE_STATE = 0;
}



SSI_INT64 String::Format(const SSI_CHAR *fmt, ...)
{
		START_PROFILE("String::Format");

		SSI_CHAR Temp[4096];
		SSI_INT64 NumFields = 0;
	  va_list vl;

		va_start( vl, fmt );
		_vsnprintf(Temp, 4096, fmt, vl);
	
		SSI_INT64 Len = strlen(Temp);
		Null();
		str = new SSI_CHAR[Len+1];
		str = (SSI_CHAR*)memcpy((void*)str, (const void*)Temp, Len);
		str[Len] = 0;

		STOP_PROFILE("String::Format");
		return 1;

/*

    SSI_INT64 Pos = -1;

    SSI_CHAR c;
    //SSI_CHAR Temp[4096];
    String Fmt = fmt;
  
    Null();

    //va_list vl;

    //   szTypes is the last argument specified; all
    //   others must be accessed using the variable-
    //   argument macros.
    va_start( vl, fmt );

    // Find the %
    // Anything before the %, add to the string
    // Switch through char after the %, and scanf into temp string
    //    Check for: %d, %s, %f, %c, 
    // Continue loop until end of format string

    while((Pos = Fmt.Find("%")) >= 0)
    {
      *this = operator+(Fmt.Left(Pos));
      Pos++;
      c = Fmt[Pos];

      union P_t
      {
        int     d;
        double  f;
        char    c;
        char   *s;
      } P;

      switch(c)
      {
      case ('d'):
        P.d = va_arg( vl, int );
        sprintf(Temp, "%d", P.d);
        Pos++;
        *this = operator+(Temp);
        NumFields++;
        break;
      case ('f'):
        P.f = va_arg( vl, double );
        sprintf(Temp, "%lf", P.f);
        Pos++;
        *this = operator+(Temp);
        NumFields++;
        break;
      case ('c'):
        P.c = va_arg( vl, char );
        sprintf(Temp, "%c", P.c);
        Pos++;
        *this = operator+(Temp);
        NumFields++;
        break;
      case ('s'):
        P.s = va_arg (vl, char*);
        while(*P.s)
        {
          sprintf(Temp, "%c", *P.s);
          P.s++;
          *this = operator+(Temp);
        }
        Pos++;
        NumFields++;
        break;
      case ('%'):
        sprintf(Temp, "%%");
        *this = operator+(Temp);
        Pos++;
        break;
      case (SSI_NULL):
        sprintf(Temp, "%%");
        *this = operator+(Temp);
        Pos++;
        break;
      default:
        sprintf(Temp, "%c", c);
        *this = operator+(Temp);
        Pos++;
        break;
      }
      Fmt = Fmt.Right(Fmt.GetLength() - Pos);
    }
    
    *this = operator+(Fmt);
    va_end( vl );
		STOP_PROFILE("String::Format");
    return NumFields;
		*/
}

void String::SetAt(SSI_INT64 Pos, SSI_CHAR c)
{
	SSI_INT64 Len = strlen(str);
  if(Pos > Len-1)
  {
    SSI_INT64 ctr = 0;
    
    SSI_CHAR* Temp = str; //new SSI_CHAR[Len+1]; 
		str = new SSI_CHAR[Pos+2]; // Must be +2 because need to append another SSI_NULL to end
		str = (SSI_CHAR*)memset((void*)str, 0, Pos+2);
		str = (SSI_CHAR*)memcpy((void*)str, (const void *)Temp, Len );
    //loc_copy(str, Temp);
		//if(str) delete str;
		//str = Temp;
		str[Pos] = c;
		str[Pos+1] = 0;
		delete [] Temp;
    //str = new SSI_CHAR[Pos+2];  // Must be +2 because need to append another SSI_NULL to end
    //for(ctr = 0; ctr < GetSize(Temp); ctr++)
    //{
    //  str[ctr] = Temp[ctr];
    //}
    //for(ctr = ctr; ctr <= Pos+1; ctr++)
    //{
    //  str[ctr] = SSI_NULL;
    //}
    //delete Temp;
	}else{
		str[Pos] = c;
	}
  //str[Pos] = c;
}

SSI_BOOL String::CheckEndQuotes(SSI_BOOL bStrip, SSI_BOOL bTrim)
{
  if(bTrim)
  {
    Trim();
  }
  if((GetAt(0) == Q_SSI_CHAR) && (GetAt(GetLength() - 1) == Q_SSI_CHAR))
  {
    if(bStrip)
    {
      chop();
      chop(1);
    }
    return 1;
  }
  return 0;
}

SSI_CHAR String::chop(SSI_BOOL bFromStart)
{
  SSI_INT64 sz = strlen(str); //GetLength();
  SSI_CHAR Ret = SSI_NULL;
  if(sz == 0) return SSI_NULL;
  if(sz == 1)
  {
    Ret = GetAt(0);
    *this = "";
    return Ret;
  }
  if(!bFromStart)
  {
    Ret = GetAt(sz - 1);
    *this = SubString(0, sz - 2);
  }
  else
  {
    Ret = GetAt(0);
    *this = SubString(1);
  }
  return Ret;
}

SSI_BOOL String::SetEndQuotes(SSI_BOOL bConvertExistingEnds)
{

  String sQSSI_CHAR;
  SSI_BOOL bRet = 0;
  //sQSSI_CHAR.Format("%c", Q_SSI_CHAR);
	sQSSI_CHAR.SetAt(0, Q_SSI_CHAR);
	
  bRet = CheckEndQuotes();
  if(!bRet)
  {
    *this = sQSSI_CHAR + *this + sQSSI_CHAR;
  }
  else
  {
    if(bConvertExistingEnds)
    {
      CheckEndQuotes(1);
      *this = sQSSI_CHAR + "\\\"" + *this + "\\\"" + sQSSI_CHAR;
    }
  }
  return bRet;
}

SSI_BOOL String::CheckChars(SSI_WORD wFlags) const
{
  SSI_CHAR c = 0;
  SSI_CHAR* t = str;
  String cStr;
  String SearchChars;

  if(wFlags & FLAG_ALPHA)
  {
    SearchChars = SearchChars + SSI_CHARS_ALPHA;
  }
  if(wFlags & FLAG_NUMERIC)
  {
    SearchChars = SearchChars + SSI_CHARS_NUMERIC;
  }
  if(wFlags & FLAG_UNDERSCORE)
  {
    SearchChars = SearchChars + SSI_CHARS_UNDERSCORE;
  }
  if(wFlags & FLAG_PERIOD)
  {
    SearchChars = SearchChars + SSI_CHARS_PERIOD;
  }
  if(wFlags & FLAG_PUNCTUATION)
  {
    SearchChars = SearchChars + SSI_CHARS_PUNCTUATION;
  }
  if(wFlags & FLAG_SPACE)
  {
    SearchChars = SearchChars + SSI_CHARS_SPACE;
  }
  if(wFlags & FLAG_WHITESPACE)
  {
    SearchChars = SearchChars + SSI_CHARS_WHITESPACE;
  }
  if(wFlags & FLAG_NEGATIVE)
  {
    SearchChars = SearchChars + SSI_CHARS_NEGATIVE;
  }
  while(*t)
  {
    c = *t;
    t++;
		cStr.SetAt(0, c);
    if(cStr.FindOneOf(SearchChars) < 0)
    {
      return 0;
    }
  }
  return 1;
}

SSI_INT64 String::FindOneOf(const String& Str, SSI_INT64 Start, SSI_INT64 Stop) const
{
	SSI_INT64 inLen = Str.GetLength();
  if(GetLength() <= 0) return -1;
  if(inLen <= 0) return -1;
  SSI_INT64 Pos = 0;
  SSI_INT64 Loc = -1;
  SSI_INT64 Ret = -1;
  String Temp;
  for(Pos = 0; Pos < inLen; Pos++)
  {
		Temp.SetAt(0, Str.GetAt(Pos));
    if((Loc = Find(Temp, Start, Stop)) >= 0)
    {
      if(Ret < 0)
      {
        Ret = Loc;
      }
      else if(Loc < Ret)
      {
        Ret = Loc;
      }
    }
  }
  return Ret;
}

void String::SetBeforeState(SSI_CHAR Char)
{
  CHECK_BEFORE_SSI_CHAR = Char;
}

void String::SetAfterState(SSI_CHAR Char)
{
  CHECK_AFTER_SSI_CHAR = Char;
}

void String::SetWithinState(SSI_CHAR StartChar, SSI_CHAR EndChar)
{
  CHECK_WITHIN_SSI_CHAR_START = StartChar;
  CHECK_WITHIN_SSI_CHAR_END = EndChar;
}

void String::Reverse()
{
	// evidently this can have some buffer overflow
	//str = strrev(str);

	START_PROFILE("String::Reverse");
  String Temp = *this;
  SSI_INT64 Len = GetLength();
  SSI_INT64 ctr = 0;
  if(!Len) return;
  while(Len)
  {
     SetAt(ctr, Temp[Len-1]);
     Len--;
     ctr++;
  }
	STOP_PROFILE("String::Reverse");
}

SSI_INT64 String::ReverseFind(const SSI_CHAR *In, SSI_INT64 StartPos, SSI_INT64 StopPos)
{
  Reverse();
  SSI_INT64 Ret = -1;
  Ret = Find(In, StopPos, StartPos);
	if(Ret < 0){
		Reverse();
		return -1;
	}
  Reverse();
  return GetLength() - Ret - 1;
}

void String::CopyToBuffer(SSI_CHAR *In) const
{
  if(In) loc_copy(str, In);
}


SSI_BOOL String::IsNumber(void)
{
	char* ptr = str;
	const char* decimal = SSI_CHARS_DECIMAL;
	const char* negative = SSI_CHARS_NEGATIVE;
	while(*ptr){
		if(!isdigit(*ptr)){
			if(*ptr != decimal[0]){
				if(*ptr != negative[0]){
					return 0;
				}
			}
		}
		ptr++;
	}
	return 1;
}

bool String::IsWhiteSpace(void)
{
	char* ptr = str;
	const char* spaces = " \t";
	while(*ptr){
		if(*ptr != spaces[0]){
			if(*ptr != spaces[1]){
				return 0;
			}
		}
		ptr++;
	}
	return 1;
}

SSI_BOOL String::GetQuoteState(void) const
{
	if(CHECK_WITHIN_SSI_CHAR_END == Q_SSI_CHAR && CHECK_WITHIN_SSI_CHAR_END == Q_SSI_CHAR){
		return 1;
	}
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// STRING2
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
#else


#include <stdio.h>
#include <stdarg.h>
#include <memory.h>
#include <String.h>
#include <ctype.h>


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

String::String()
{
  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;
}

String::String(const SSI_CHAR* InitVal)
{

  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;

  if(InitVal){
	  str = InitVal;
  }else{
    str = "";
  }
	//SSI_INT64 Len = strlen(str.c_str());

	// This will always be null
	//if(str) delete str;
  //str = new SSI_CHAR[Len+1];  
	//str = (SSI_CHAR*)memcpy( (void*)str, (const void *)InitVal, Len );
	//str[Len] = SSI_NULL;

}

String::String(SSI_CHAR InitChar)
{
  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;
  
	str = InitChar;

}

String::String(const String& Other)
{
	START_PROFILE("String::String(Other)");

  CHECK_WITHIN_SSI_CHAR_START = 0;
  CHECK_WITHIN_SSI_CHAR_END = 0;
  CHECK_BEFORE_SSI_CHAR = 0;
  CHECK_AFTER_SSI_CHAR = 0;

	str = Other.str;

	//SSI_INT64 Len = strlen(Other.str);
	// This will always be null
	//if(str) delete str;
  //str = new SSI_CHAR[Len+1];  
	//str = (SSI_CHAR*)memcpy( (void*)str, (const void *)Other.str, Len );
	//str[Len] = SSI_NULL;
	
  //str = SSI_NULL;
  //SSI_INT64 Len = GetSize(Other.str);
  //str = new SSI_CHAR[Len+1];
	//loc_copy(Other.str, str);

	STOP_PROFILE("String::String(Other)");
}

String::~String()
{
  Null();
}

SSI_CHAR* String::Null()
{
  //if(str)
  //{
  //  delete [] str;
  //  str = SSI_NULL;
  //}
  //return str;
	//str.clear();
	str = "";
	return 0;
}

SSI_INT64 String::GetSize(const SSI_CHAR *InStr)
{

	//return str.size();
	if(InStr == SSI_NULL) return 0;
  SSI_INT64 Ret = (SSI_INT64)strlen(InStr);
	return Ret;

  //while(*InStr++ != SSI_NULL)
  //{
  //  Ret++;
  //}
  //return Ret;
}

const SSI_CHAR* String::Str() const
{
	return str.c_str();
}

//SSI_INT64 String::loc_copy(const SSI_CHAR *src, SSI_CHAR *dest)
//{
//  if(src == SSI_NULL) return SSI_NULL;
//  if(dest == SSI_NULL) return SSI_NULL;
//
//  SSI_INT64 Len = 0;
//  Len = GetSize(src);
//
//  dest = (SSI_CHAR*)memcpy( (void*)dest, (const void *)src, Len );
//  dest[Len] = SSI_NULL;
//  return Len;
//}

String& String::operator =(const String& Other)
{
	str = Other.str;

//	START_PROFILE("String::=(Other)");
//	SSI_INT64 Len = strlen(Other.str);
//	Null();
//  str = new SSI_CHAR[Len+1];  
//	str = (SSI_CHAR*)memcpy( (void*)str, (const void *)Other.str, Len );
//	str[Len] = SSI_NULL;
//	STOP_PROFILE("String::=(Other)");
  return *this;
}

String& String::operator =(const SSI_CHAR* Other)
{
	str = Other;

	//START_PROFILE("String::=(cchar)");
	//SSI_INT64 Len = strlen(Other);
	//Null();
  //str = new SSI_CHAR[Len+1];  
	//str = (SSI_CHAR*)memcpy( (void*)str, (const void *)Other, Len );
	//str[Len] = SSI_NULL;
	//STOP_PROFILE("String::=(cchar)");
	return *this;
}

bool String::operator<(const String& Other) const
{
	if(strcmp(str.c_str(), Other.str.c_str()) < 0){
		return true;
	}
	return false;
}

bool String::operator<(const SSI_CHAR* Other) const
{
	if(strcmp(str.c_str(), Other) < 0){
		return true;
	}
	return false;
}


// I changed this to a const &
String String::operator +(const String& s2)
{
	String ret;
	//ret.str = str.c_str();
  ret.str = str + s2.str;  // JCV CHANGED ON 11/15/08
	//ret.str += s2.str.c_str();
	return ret;
	
		
	//START_PROFILE("String::+(Other)");
  //SSI_INT64 iLen1 = GetLength();
  //SSI_INT64 iLen2 = s2.GetLength();
  //SSI_INT64 ctr = 0;
  //SSI_CHAR* Temp = new SSI_CHAR[iLen1+iLen2+1];

  //for(ctr = 0; ctr < iLen1; ctr++)
  //{
  //  Temp[ctr] = str[ctr];
  //}
  //for(ctr = iLen1; ctr < (iLen1+iLen2); ctr++)
  //{
  //  Temp[ctr] = s2[ctr-iLen1];
  //}
  //Temp[ctr] = SSI_NULL;
	//String Ret = Temp;
	//delete [] Temp;
  //STOP_PROFILE("String::+(Other)");
	//return Ret;
}

String String::operator +(SSI_CHAR* s2)
{
	String ret;
  ret.str = str + s2; // JCV CHANGED ON 11/15/08
	//ret.str = str.c_str();
	//ret.str += s2;
	return ret;

  //return operator+(String(s2));
}

/*
SSI_CHAR& String::operator [](SSI_INT64 i)
{
  if(i > GetSize(str)-1)
  {
    SSI_INT64 ctr = 0;
    
    SSI_CHAR* Temp = new SSI_CHAR[GetLength()+1];
    loc_copy(str, Temp);

    Null();
    str = new SSI_CHAR[i+2];  // Must be +2 because need to append another SSI_NULL to end
    for(ctr = 0; ctr < GetSize(Temp); ctr++)
    {
      str[ctr] = Temp[ctr];
    }
    for(ctr = ctr; ctr <= i+1; ctr++)
    {
      str[ctr] = SSI_NULL;
    }
    delete Temp;
  }
  return str[i];
}
*/

SSI_INT64 String::GetLength() const
{
	//if(!str) return 0;
	//SSI_INT64 Ret = strlen(str.c_str());
	//return Ret;
  return strlen(str.c_str());
	//return strlen(str.c_str());
  //return GetSize(str);
}


SSI_BOOL String::operator ==(String &Other) const
{
  // It may be slightly quicker to keep these checks
	//SSI_INT64 i1 = strlen(str);        //GetLength();
	//SSI_INT64 i2 = strlen(Other.str);  //Other.GetLength();

	if(strcmp(str.c_str(), Other.str.c_str())){
		return 0;
	}
	return 1;


	//if(str.compare(Other.str)){
	//	return 0;
	//}
	//return 1;
	//if(strcmp(str, Other.str)){
	//	return 0;
	//}else{
	//	return 1;
	//}
}

SSI_BOOL String::operator ==(const SSI_CHAR* Other) const
{

	if(strcmp(str.c_str(), Other)){
		return 0;
	}
	return 1;

	//if(str.compare(Other)){
	//	return 0;
	//}
	//return 1;

	//if(strcmp(str, Other)){
	//	return 0;
	//}else{
	//	return 1;
	//}
}

void String::replace(string& s_in, const SSI_CHAR *Out, const SSI_CHAR *In){
	SSI_INT64 pos = 0;
	SSI_INT64 len_out = strlen(Out);
	SSI_INT64 len_in = strlen(In);
	while((pos = s_in.find(Out, pos)) >= 0){
		s_in.replace(pos, len_out, In);
		pos = pos + len_in;
	}
}

// Changed this to void... see if return value used
void String::Replace(const SSI_CHAR *Out, const SSI_CHAR *In)
{
	replace(str, Out, In);
	//str.replace(Out, In);

//	START_PROFILE("String::Replace");
//  SSI_INT64 Ret = 0;
//  SSI_INT64 iOut = strlen(Out);//GetSize(Out);
//  SSI_INT64 iIn = strlen(In);  //GetSize(In);
//  SSI_INT64 ctr = 0;
//
//  SSI_INT64 Sz = strlen(str);  //GetLength();
//  
//  String T2;
//  String T3;
//
//  if(Sz < iOut) return 0;
//
//  for(ctr = 0; ctr < Sz; ctr++)
//  {
//    T3 = SubString(ctr, ctr + iOut - 1);
//    if(T3 == Out)
//    {
//        if(ctr > 0)
//        {
//          T2 = SubString(0, ctr-1);
//        }
//        T3 = SubString(ctr + iOut, Sz);
//        T2 = T2 + In + T3;
//        *this = T2;
//        ctr = ctr + iIn - 1;
//        Sz = GetLength();
//        Ret++;
//    }
//  }
//	STOP_PROFILE("String::Replace");
//  return Ret;
}

String String::SubString(SSI_INT64 Start, SSI_INT64 Finish) const
{
	String Ret;
	SSI_INT64 Len = strlen(str.c_str());
	if((Finish < 0) || (Finish > (Len - 1))) Finish = Len;
	if(Start < 0) Start = 0;
	if(Start > Finish){
		return String("");
	}
	if(Start >= Len){
		return String("");
	}
	Ret.str = str.substr(Start, Finish-Start+1);  // Because it is inclusive of the ends
	return Ret;

	//START_PROFILE("String::SubString");
	//SSI_INT64 Len = strlen(str);
  //if((Finish < 0) || (Finish > (Len - 1))) Finish = Len - 1;
  //if(Start < 0) Start = 0;
  //if(Start > Finish)
  //{
	//	return String(""); // An empty string
  //}
	//SSI_CHAR oc = str[Finish+1];  // This is inclusive
	//SSI_CHAR* temp = str + Start;
	//str[Finish+1] = 0;
	//String Ret;
	//Ret = temp;
	//str[Finish+1] = oc;
	//STOP_PROFILE("String::SubString");
	//return Ret;
}

// Redo this one still
SSI_INT64 String::Find(const String &In, SSI_INT64 StartPos, SSI_INT64 StopPos) const
{
  // This whole function could be made quicker...
  // Actually, it is probably as quick as it can get, and still 
	//  do the quote processing, etc...

	// Temporarily replace all \\\\ with sp

	SSI_INT64 ilen = strlen(str.c_str());

	if(ilen <= 0){
		return -1;
	}

	if(strlen(In.str.c_str()) <= 0){
		return -1;
	}

	if(StopPos < 0){
		StopPos = ilen;
	}
	if(StopPos > ilen){
		StopPos = ilen;
	}

	if(StartPos < 0){
		StartPos = 0;
	}
	if(StartPos > ilen){
		return -1;
	}

	const char* esc = "\\\\";
	char sp2[3];
	sp2[0] = 1;
	sp2[1] = 1;
	sp2[2] = 0;
	char bDoCheck = 0;

	SSI_BOOL qCtr = 0;

	string s = str.substr(StartPos, StopPos - StartPos);
	string sq;

	replace(s, (const char*)esc, sp2);
	if(CHECK_WITHIN_SSI_CHAR_START && CHECK_WITHIN_SSI_CHAR_END){
		bDoCheck = 1;
	}

	SSI_INT64 ioff = 0;
	SSI_INT64 ipos = -1;
	SSI_INT64 qpos = 0;

	ipos = s.find(In.str);  // Already substringed
	while(ipos >= 0){
		if(bDoCheck){
			sq = s.substr(0, ipos);
			//sq = s.substr(0, ipos-1);  // -1 because dont want to include first char of search
			while((qpos = sq.find(CHECK_WITHIN_SSI_CHAR_START, qpos)) >= 0){
				qCtr++;
				while(1){
					qpos = sq.find(CHECK_WITHIN_SSI_CHAR_END, qpos+1);
					if(qpos > 0){
						if(sq[qpos-1] != ESCAPE_SSI_CHAR){
							qCtr++;
							qpos = qpos + 1;
							break;  // Found the end quote, co continue finding beginning quotes
						}
						// Else keep finding
					}else if(qpos == 0){
						qCtr++;
						qpos = qpos + 1;
						break;    // Found end quote here too...
					}else if(qpos < 0){  // Never found end quote, so found item is in quotes
						break;
					}
				}
			}
			if(qCtr % 2){
			}else{
				return ipos + StartPos;        // item found, so return it.
			}

		}else{
			return ipos + StartPos;
		}
		ipos = s.find(In.str, ipos+1);  // Find from next position
		qpos = 0;
		qCtr = 0;
	}
	return -1;
	

	// basically, str.find()
	//   if check quotes count quotes to left, do mod
	//   


//	SSI_INT64 len = GetLength();
//	if(len <= 0) return -1;
//	char *pdest;

//	SSI_INT64 Ret = -1;
//	char sp2[3];
//	sp2[0] = 1;
//	sp2[1] = 1;
//	sp2[2] = 0;
//	char* esc = "\\\\";
	
//	String s;
//	s = str;

//	int offset = 0;
	
//	SSI_INT64 i = s.Replace(esc, sp2);

	/*
	offset = StartPos-1;
	int qoffset = 0;
	int qctr = 0;

	char *qdest;
	char t = 0;
	char check[2];
	check[0] = CHECK_WITHIN_SSI_CHAR_START;
	check[1] = 0;
	char bDoCheck = 0;
	int bGo = 1;

	if(offset < -1){
		offset = -1;
	}else if(offset >= len){
		offset = GetLength();
	}

	if(StopPos >= len){
		StopPos = len;
	}

	if(CHECK_WITHIN_SSI_CHAR_START && CHECK_WITHIN_SSI_CHAR_END){
		bDoCheck = 1;
	}

	if(StopPos >= 0){
		s.str[StopPos] = 0;  // avoid going past the stop position
	}
	while((pdest = strstr(s.str + offset + 1, In.str)) && bGo){
		offset = (int)(pdest - s.str);
		
		t = s.str[offset];
		s.str[offset] = 0;

		// Check if within start chars
		qoffset = -1;
		qctr = 0;
		if(bDoCheck){
			while(qdest = strstr(s.str + qoffset + 1, check)){
				qoffset = (int)(qdest - s.str);
				if(check[0] == CHECK_WITHIN_SSI_CHAR_END){
					if(s.str[qoffset - 1] == ESCAPE_SSI_CHAR){
					}else{
						qctr++;
					}
				}else{
					qctr++;
				}
				if(qctr % 2){
					check[0] = CHECK_WITHIN_SSI_CHAR_START;
				}else{
					check[0] = CHECK_WITHIN_SSI_CHAR_END;
				}				
			}
		}

		// See if char on opposite side
		if(qctr % 2){
		}else{
			Ret = offset;
			bGo = 0;
		}
		s.str[offset] = t;
	}

	return Ret;
	*/
}

SSI_INT64 String::Find(const SSI_CHAR* In, SSI_INT64 StartPos, SSI_INT64 StopPos) const
{
  return Find(String(In), StartPos, StopPos);
}

String String::Left(SSI_INT64 NumChars) const
//String String::Left(SSI_INT64 NumChars)
{
	String Ret = "";
	if(NumChars <= 0){
		return Ret;
	}
  if(NumChars > strlen(str.c_str())){
    return Ret;
  }
  //if(NumChars <= 0)
  //{
  //  return "";
  //}
	//return Ret;


  // JCV CHANGED ON 11/15/08
 	//Ret.str = str.substr(0, NumChars-1);  // Because it is inclusive of the ends
	//return Ret;


	return SubString(0, NumChars-1);
  //return String(SubString(0, NumChars-1));
}

String String::Right(SSI_INT64 NumChars) const
{
	
	SSI_INT64 Len = strlen(str.c_str());
	// JCV CHANGED ON 11/15/08
  //String Ret;
  //if(Len-NumChars > strlen(str.c_str())){
  //  Ret.str = str;
  //}else{
  // 	Ret.str = str.substr(Len-NumChars);  // Because it is inclusive of the ends
  //}
	//return Ret;

  
  return SubString(Len - NumChars);
  //SSI_INT64 Len = strlen(str);  //GetLength();
  //return String(SubString(Len - NumChars));
  // BECAUSE REMEMBER SubString is INCLUSIVE
}

//SSI_INT64 String::Parse(const char* Delimeters, String &Return, String* Tok, SSI_INT64 DelLen){
//	return Parse(String(Delimeters), Return, Tok, DelLen);
//}

SSI_INT64 String::Parse(String& Delimeters, StringTree& Return, SSI_INT64 DelLen){
	SSI_INT64 ctr = 1;        // There will be at least one
	String RetStr;
	while(Parse(Delimeters, RetStr, 0, DelLen) >= 0){
		Return.push(RetStr);
		ctr++;
	}
	Return.push(*this);   // Add the last element
	return ctr;
}


SSI_INT64 String::Parse(String& Delimeters, String &Return, String* Tok, SSI_INT64 DelLen)
{

	SSI_INT64 Len = strlen(Delimeters.str.c_str()); //Delimeters.str.length();
  if(DelLen < 1) DelLen = 1;
  if(DelLen > Len) DelLen = Len;
  if(Len == 0) return -1;
	SSI_INT64 i = 0;
  SSI_INT64 Pos = 0;
  SSI_INT64 Min = -1;

	// Can this be made quicker?
	for(i = 0; i < Len; i){
    if( (Pos = Find( Delimeters.SubString( i, i+DelLen-1 ) ))  >= 0){
      if((Pos < Min) || (Min < 0)){
        Min = Pos;
        if(Tok){
          *Tok = SubString(Pos, Pos+DelLen-1);
        }
      } 
    }

    // Make sure it accounts for the DelLen
    i = i + DelLen;
    if(i > (Len-1)) break;
    if((i + DelLen-1) > (Len-1)) break;
  }
  if(Min == 0){
    Return = "";
    //*this = SubString(Min+DelLen);
		str = SubString(Min+DelLen).str;
    return 0;
  }else if(Min < 0){
    Return = "";
    return -1;
  }else{
		Return = SubString(0, Min-1);
    //*this = SubString(Min+DelLen);
		string s = SubString(Min+DelLen).str;
    
		str = s;

    //Reverse();
    //Reverse();

    return Min;
  }  


	//  This is probably as optimal as it will get...
//  SSI_INT64 Len = strlen(Delimeters.str);  //Delimeters.GetLength();
//  if(DelLen < 1) DelLen = 1;
//  if(DelLen > Len) DelLen = Len;

//  if(Len == 0) return -1;
//  SSI_INT64 i = 0;
//  SSI_INT64 Pos = 0;
//  SSI_INT64 Min = -1;
//  for(i = 0; i < Len; i++)
//  {
//    if( (Pos = Find( Delimeters.SubString( i, i+DelLen-1 ) ))  >= 0)
//    {
//      if((Pos < Min) || (Min < 0))
//      {
//        Min = Pos;
//        if(Tok)
//        {
//          *Tok = SubString(Pos, Pos+DelLen-1);
//        }
//      } 
//    }
//  }
//  if(Min == 0)
//  {
//    Return = "";
//    *this = SubString(Min+DelLen);
//    return 0;
//  }
//  else if(Min < 0)
//  {
//    Return = "";
//    return -1;
//  }
//  else
//  {
//	Return = SubString(0, Min-1);
//    *this = SubString(Min+DelLen);
//    return Min;
//  }  
}

void String::TrimLeft()
{
	SSI_INT64 spos = str.find_first_not_of("\t \n\r");
	if(spos > 0){
		str = str.substr(spos);
	}else if(spos < 0){
		str = "";
	}

 // SSI_INT64 Len = strlen(str);  //GetLength();
 // SSI_INT64 i;
 // SSI_INT64 Pos = -1;
 // if(Len <= 0) return;
 // for(i = 0; i < Len; i++)
 // {
 //   SSI_CHAR T = str[i];  //GetAt(i);
 //   if((T != '\t') && (T != ' '))
 //   {
 //     break;
 //   }
 //   else
 //   {
 //     Pos = i;
 //   }
 // }
 // if(Pos < 0) return;
 // *this = SubString(Pos+1);
}

void String::TrimRight()
{
	SSI_INT64 spos = str.find_last_not_of("\t \n\r");
	if(spos >= 0){
		str = str.substr(0, spos+1);  // +1 because it is a length
	}else if(spos < 0){
		str = "";
	}

//  SSI_INT64 Len = strlen(str);//GetLength();
//  SSI_INT64 i;
//  SSI_INT64 Pos = -1;
//  if(Len <= 0) return;
//  for(i = Len-1; i >= 0; i--)
//  {
//    SSI_CHAR T = str[i];//GetAt(i);
//    if((T != '\t') && (T != ' '))
//    {
//      break;
//    }
//    else
//    {
//      Pos = i;
//    }
//  }
//  if(Pos == 0) *this = "";
//  else if(Pos < 0) return;
//  else *this = SubString(0, Pos-1);
}

void String::Trim()
{
  TrimLeft();
  TrimRight();
}

SSI_CHAR String::GetAt(SSI_INT64 Pos) const
{
	if(Pos < 0) return SSI_NULL;
	if((unsigned int)Pos > strlen(str.c_str())) return SSI_NULL;
	return str[Pos];

//  if(Pos > static_cast<SSI_INT64>(strlen(str))) return SSI_NULL;
//  if(Pos < 0) return SSI_NULL;
//  return str[Pos];  
}

void String::SetQuoteState(SSI_BOOL bSet)
{
  if(bSet) CHECK_WITHIN_SSI_CHAR_END = CHECK_WITHIN_SSI_CHAR_START = Q_SSI_CHAR;
  else CHECK_WITHIN_SSI_CHAR_END = CHECK_WITHIN_SSI_CHAR_START = SSI_NULL;
}



SSI_INT64 String::Format(const SSI_CHAR *fmt, ...)
{
	// Something needs to be done about this...
	//str.

//		START_PROFILE("String::Format");
//

  va_list vl;
  int sz = 1024;
  int ctr = 0;

  SSI_CHAR* Temp = SSI_NULL;

  while(1){
    if(Temp){
      delete [] Temp;
      Temp = SSI_NULL;
    }
    Temp = new SSI_CHAR[sz];
		va_start( vl, fmt );
		_vsnprintf(Temp, sz, fmt, vl);
	  va_end(vl);

    SSI_INT64 Len = strlen(Temp);
    Temp[Len] = 0;
    if(Len < sz){
      break;
    }else{
      sz = sz * 2;
      ctr++;
    }
    if(ctr > 14){
      break;
    }
  }

  str = Temp;
  delete [] Temp;
  Temp = SSI_NULL;



//		SSI_CHAR Temp[4096];
//	  va_list vl;
//
//		va_start( vl, fmt );
//		_vsnprintf(Temp, 4096, fmt, vl);
//	  va_end(vl);
//
//   SSI_INT64 Len = strlen(Temp);
//    if(Len > 4096){
//      return 0;
//    }
//
//		str = Temp;
		return 1;
}

// Changed the return type from void
// Look for calls to see how used
SSI_INT64 String::SetAt(SSI_INT64 Pos, SSI_CHAR c)
{
	SSI_INT64 Len = strlen(str.c_str());
	if(Pos > Len-1){
		str.resize(Len + (Pos-Len+1));
		//return -1;
	}
	if(Pos < 0){
		return -1;
	}
	str[Pos] = c;
	return 1;


	//SSI_INT64 Len = strlen(str);
  //if(Pos > Len-1)
  //{
  //  SSI_INT64 ctr = 0;
  //  
  //  SSI_CHAR* Temp = str; //new SSI_CHAR[Len+1]; 
	//	str = new SSI_CHAR[Pos+2]; // Must be +2 because need to append another SSI_NULL to end
	//	str = (SSI_CHAR*)memset((void*)str, 0, Pos+2);
	//	str = (SSI_CHAR*)memcpy((void*)str, (const void *)Temp, Len );
	//	str[Pos] = c;
	//	str[Pos+1] = 0;
	//	delete [] Temp;
	//}else{
	//	str[Pos] = c;
	//}
}

SSI_BOOL String::CheckEndQuotes(SSI_BOOL bStrip, SSI_BOOL bTrim)
{
  if(bTrim){
    Trim();
  }

	if(strlen(str.c_str()) <= 0) return 0;

	if((str[0] == Q_SSI_CHAR) && (str[strlen(str.c_str()) - 1] == Q_SSI_CHAR)){
    if(bStrip){
      chop();
      chop(1);
    }
		return 1;
	}

	return 0;

//  if((GetAt(0) == Q_SSI_CHAR) && (GetAt(GetLength() - 1) == Q_SSI_CHAR))
// {
//    if(bStrip)
//    {
//      chop();
//      chop(1);
//    }
//    return 1;
//  }
//  return 0;
}

SSI_CHAR String::chop(SSI_BOOL bFromStart)
{
	SSI_CHAR Ret = SSI_NULL;
	SSI_INT64 sz = strlen(str.c_str());
	if(sz <= 0) return 0;
	if(bFromStart){
		Ret = str[0];
		str = str.substr(1, sz - 1);
	}else{
		Ret = str[sz-1];
		str = str.substr(0, sz - 1);
	}
	return Ret;

//  SSI_INT64 sz = strlen(str); //GetLength();
//  SSI_CHAR Ret = SSI_NULL;
//  if(sz == 0) return SSI_NULL;
//  if(sz == 1)
//  {
//    Ret = GetAt(0);
//    *this = "";
//    return Ret;
//  }
//  if(!bFromStart)
//  {
//    Ret = GetAt(sz - 1);
//    *this = SubString(0, sz - 2);
//  }
//  else
//  {
//    Ret = GetAt(0);
//    *this = SubString(1);
//  }
//  return Ret;
}

SSI_BOOL String::SetEndQuotes(SSI_BOOL bConvertExistingEnds)
{

  String sQSSI_CHAR;
  SSI_BOOL bRet = 0;
	sQSSI_CHAR.SetAt(0, Q_SSI_CHAR);
	
  bRet = CheckEndQuotes();
  if(!bRet)
  {
    *this = sQSSI_CHAR + *this + sQSSI_CHAR;
  }
  else
  {
    if(bConvertExistingEnds)
    {
      CheckEndQuotes(1);
      *this = sQSSI_CHAR + "\\\"" + *this + "\\\"" + sQSSI_CHAR;
    }
  }
  return bRet;
}

SSI_BOOL String::CheckChars(SSI_WORD wFlags) const
{

  SSI_CHAR c = 0;
  String cStr;
  String SearchChars;

  if(wFlags & FLAG_ALPHA)
  {
    SearchChars = SearchChars + SSI_CHARS_ALPHA;
  }
  if(wFlags & FLAG_NUMERIC)
  {
    SearchChars = SearchChars + SSI_CHARS_NUMERIC;
  }
  if(wFlags & FLAG_UNDERSCORE)
  {
    SearchChars = SearchChars + SSI_CHARS_UNDERSCORE;
  }
  if(wFlags & FLAG_PERIOD)
  {
    SearchChars = SearchChars + SSI_CHARS_PERIOD;
  }
  if(wFlags & FLAG_PUNCTUATION)
  {
    SearchChars = SearchChars + SSI_CHARS_PUNCTUATION;
  }
  if(wFlags & FLAG_SPACE)
  {
    SearchChars = SearchChars + SSI_CHARS_SPACE;
  }
  if(wFlags & FLAG_WHITESPACE)
  {
    SearchChars = SearchChars + SSI_CHARS_WHITESPACE;
  }
  if(wFlags & FLAG_NEGATIVE)
  {
    SearchChars = SearchChars + SSI_CHARS_NEGATIVE;
  }

	if(str.find_first_not_of(SearchChars.str) != string::npos){
		return 0;
	}

  //while(*t)
  //{
  //  c = *t;
  //  t++;
	//	cStr.SetAt(0, c);
  //  if(cStr.FindOneOf(SearchChars) < 0)
  //  {
  //    return 0;
  //  }
  //}
  return 1;
}

SSI_INT64 String::FindOneOf(const String& Str, SSI_INT64 Start) const
{
	// Because this requires quote_state
	//if(Start < 0) Start = 0;
	//SSI_INT64 Ret = str.find_first_of(Str.str.c_str(), Start);
	//return Ret;

	SSI_INT64 inLen = Str.GetLength();
  if(GetLength() <= 0) return -1;
  if(inLen <= 0) return -1;
  SSI_INT64 Pos = 0;
  SSI_INT64 Loc = -1;
  SSI_INT64 Ret = -1;
  String Temp;
  for(Pos = 0; Pos < inLen; Pos++){
		Temp.SetAt(0, Str.GetAt(Pos));
    if((Loc = Find(Temp, Start)) >= 0){
      if(Ret < 0){
        Ret = Loc;
      }
      else if(Loc < Ret){
        Ret = Loc;
      }
    }
  }
  return Ret;
}

void String::SetBeforeState(SSI_CHAR Char)
{
  CHECK_BEFORE_SSI_CHAR = Char;
}

void String::SetAfterState(SSI_CHAR Char)
{
  CHECK_AFTER_SSI_CHAR = Char;
}

//void String::SetWithinState(SSI_CHAR StartChar, SSI_CHAR EndChar)
//{
//  CHECK_WITHIN_SSI_CHAR_START = StartChar;
//  CHECK_WITHIN_SSI_CHAR_END = EndChar;
//}

void String::Reverse()
{
	// Should replace this... there must be a way to reverse a string
	//str = strrev(str.c_str());
	reverse(str.begin(), str.end());
	// evidently this can have some buffer overflow
	//str = strrev(str);

	//START_PROFILE("String::Reverse");
  //String Temp = *this;
  //SSI_INT64 Len = GetLength();
  //SSI_INT64 ctr = 0;
  //if(!Len) return;
  //while(Len)
  //{
  //   SetAt(ctr, Temp[Len-1]);
  //   Len--;
  //   ctr++;
  //}
	//STOP_PROFILE("String::Reverse");
}

SSI_INT64 String::ReverseFind(const SSI_CHAR *In, SSI_INT64 StartPos)
{
	//str.rfind(In, StartPos, StopPos - StartPos);
	//Reverse();

	if(StartPos < 0) StartPos = 0;

  Reverse();
  SSI_INT64 Ret = -1;
  Ret = Find(In, StartPos);
	if(Ret < 0){
		Reverse();
		return -1;
	}
  Reverse();
  return GetLength() - Ret - 1;
}

//void String::CopyToBuffer(SSI_CHAR *In) const
//{
//	if(In){
//		memcpy(In, str.c_str(), str.length());
//	}
//  //if(In) loc_copy(str, In);
//}


SSI_BOOL String::IsNumber(void)
{
	//char* ptr = str;
	//const char* decimal = SSI_CHARS_DECIMAL;
	//const char* negative = SSI_CHARS_NEGATIVE;
	
	string sfind = SSI_CHARS_DECIMAL;
	sfind = SSI_CHARS_NEGATIVE;
	int i;
	if((i = str.find_first_not_of(sfind)) >= 0){
		return 0;
	}
	return 1;

	//while(*ptr){
	//	if(!isdigit(*ptr)){
	//		if(*ptr != decimal[0]){
	//			if(*ptr != negative[0]){
	//				return 0;
	//			}
	//		}
	//	}
	//	ptr++;
	//}
	//return 1;
}

bool String::IsWhiteSpace(void)
{
	//char* ptr = str;
	const char* spaces = " \t";
	int i;
	if((i = str.find_first_not_of(spaces)) >= 0){
		return 0;
	}
	return 1;
	
	//while(*ptr){
	//	if(*ptr != spaces[0]){
	//		if(*ptr != spaces[1]){
	//			return 0;
	//		}
	//	}
	//	ptr++;
	//}
	//return 1;
}

SSI_BOOL String::GetQuoteState(void) const
{
	if(CHECK_WITHIN_SSI_CHAR_END == Q_SSI_CHAR && CHECK_WITHIN_SSI_CHAR_END == Q_SSI_CHAR){
		return 1;
	}
	return 0;
}

void String::ToUpper(void)
{
  std::transform (str.begin(), str.end(), str.begin(), ::toupper);
}

void String::ToLower(void)
{
  std::transform (str.begin(), str.end(), str.begin(), ::tolower);
}


#endif






